"""异常定义和全局异常处理"""
from typing import Optional, Any
from flask import Flask, request
from flask_babel import gettext as _
from werkzeug.exceptions import HTTPException
from marshmallow import ValidationError
from sqlalchemy.exc import SQLAlchemyError
from jwt.exceptions import InvalidTokenError, ExpiredSignatureError

from app.status_codes import StatusCode, HttpStatusCode
from app.responses import error_response
from app.logs import logger


class ApiException(Exception):
    """自定义API异常基类"""
    
    def __init__(
        self,
        message: Optional[str] = None,
        code: StatusCode = StatusCode.INTERNAL_ERROR,
        http_status: int = HttpStatusCode.INTERNAL_SERVER_ERROR,
        data: Any = None
    ):
        self.message = message
        self.code = code
        self.http_status = http_status
        self.data = data
        super().__init__(self.message)


class ValidationException(ApiException):
    """参数验证异常"""
    
    def __init__(self, message: Optional[str] = None, data: Any = None):
        super().__init__(
            message=message,
            code=StatusCode.INVALID_PARAMS,
            http_status=HttpStatusCode.BAD_REQUEST,
            data=data
        )


class AuthenticationException(ApiException):
    """认证异常"""
    
    def __init__(self, message: Optional[str] = None):
        super().__init__(
            message=message,
            code=StatusCode.UNAUTHORIZED,
            http_status=HttpStatusCode.UNAUTHORIZED
        )


class AuthorizationException(ApiException):
    """授权异常"""
    
    def __init__(self, message: Optional[str] = None):
        super().__init__(
            message=message,
            code=StatusCode.FORBIDDEN,
            http_status=HttpStatusCode.FORBIDDEN
        )


class ResourceNotFoundException(ApiException):
    """资源不存在异常"""
    
    def __init__(self, message: Optional[str] = None):
        super().__init__(
            message=message,
            code=StatusCode.RESOURCE_NOT_FOUND,
            http_status=HttpStatusCode.NOT_FOUND
        )


class UserNotFoundException(ApiException):
    """用户不存在异常"""
    
    def __init__(self, message: Optional[str] = None):
        super().__init__(
            message=message,
            code=StatusCode.USER_NOT_FOUND,
            http_status=HttpStatusCode.NOT_FOUND
        )


class UserAlreadyExistsException(ApiException):
    """用户已存在异常"""
    
    def __init__(self, message: Optional[str] = None):
        super().__init__(
            message=message,
            code=StatusCode.USER_ALREADY_EXISTS,
            http_status=HttpStatusCode.CONFLICT
        )


class DatabaseException(ApiException):
    """数据库异常"""
    
    def __init__(self, message: Optional[str] = None):
        super().__init__(
            message=message,
            code=StatusCode.DATABASE_ERROR,
            http_status=HttpStatusCode.INTERNAL_SERVER_ERROR
        )


def register_error_handlers(app: Flask) -> None:
    """注册全局异常处理器"""
    
    @app.errorhandler(ApiException)
    def handle_api_exception(error: ApiException):
        """处理自定义API异常"""
        logger.warning(f"API异常: {error.message}, 代码: {error.code.code}, 请求路径: {request.path}")
        return error_response(
            message=error.message,
            code=error.code,
            http_status=error.http_status,
            data=error.data
        )
    
    @app.errorhandler(ValidationError)
    def handle_validation_error(error: ValidationError):
        """处理Marshmallow验证错误"""
        logger.warning(f"参数验证错误: {error.messages}, 请求路径: {request.path}")
        return error_response(
            message=_("参数验证失败"),
            code=StatusCode.INVALID_PARAMS,
            http_status=HttpStatusCode.BAD_REQUEST,
            data=error.messages
        )
    
    @app.errorhandler(HTTPException)
    def handle_http_exception(error: HTTPException):
        """处理HTTP异常"""
        logger.warning(f"HTTP异常: {error.description}, 状态码: {error.code}, 请求路径: {request.path}")
        
        # 映射HTTP状态码到业务状态码
        status_code_mapping = {
            400: StatusCode.INVALID_PARAMS,
            401: StatusCode.UNAUTHORIZED,
            403: StatusCode.FORBIDDEN,
            404: StatusCode.RESOURCE_NOT_FOUND,
            405: StatusCode.INVALID_PARAMS,
            422: StatusCode.INVALID_PARAMS,
        }
        
        business_code = status_code_mapping.get(error.code, StatusCode.INTERNAL_ERROR)
        
        return error_response(
            message=error.description,
            code=business_code,
            http_status=error.code
        )
    
    @app.errorhandler(SQLAlchemyError)
    def handle_database_error(error: SQLAlchemyError):
        """处理数据库错误"""
        logger.error(f"数据库错误: {str(error)}, 请求路径: {request.path}")
        return error_response(
            message=_("数据库操作失败"),
            code=StatusCode.DATABASE_ERROR,
            http_status=HttpStatusCode.INTERNAL_SERVER_ERROR
        )
    
    @app.errorhandler(InvalidTokenError)
    def handle_invalid_token_error(error: InvalidTokenError):
        """处理JWT无效令牌错误"""
        logger.warning(f"无效令牌: {str(error)}, 请求路径: {request.path}")
        return error_response(
            message=_("无效的令牌"),
            code=StatusCode.INVALID_TOKEN,
            http_status=HttpStatusCode.UNAUTHORIZED
        )
    
    @app.errorhandler(ExpiredSignatureError)
    def handle_expired_token_error(error: ExpiredSignatureError):
        """处理JWT令牌过期错误"""
        logger.warning(f"令牌过期: {str(error)}, 请求路径: {request.path}")
        return error_response(
            message=_("令牌已过期"),
            code=StatusCode.TOKEN_EXPIRED,
            http_status=HttpStatusCode.UNAUTHORIZED
        )
    
    @app.errorhandler(Exception)
    def handle_generic_exception(error: Exception):
        """处理通用异常"""
        logger.error(f"未处理的异常: {str(error)}, 请求路径: {request.path}", exc_info=True)
        return error_response(
            message=_("服务器内部错误"),
            code=StatusCode.INTERNAL_ERROR,
            http_status=HttpStatusCode.INTERNAL_SERVER_ERROR
        ) 